package isssr.dao.hibernate;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.hibernate.Query;
import org.hibernate.Session;

public class QueryBuilder implements Serializable {
	
	private boolean firstParameter;
	
	public QueryBuilder()
	{
		this.firstParameter = true;
	}
	
	private String initQueryString(String clazzName)
	{
		return "select o from " + clazzName + " as o";
	}
	
	private String getQueryStringParameter(Entry<String, Object> parameter)
	{
		String queryString;
		String queryLink;
		
		
		if(parameter.getValue() instanceof Collection)
		{
			queryString = getQueryStringParameter_collectionParameter(parameter.getKey(), (Collection)parameter.getValue());
		}
		else if(parameter.getValue() instanceof String)
		{
			queryString = getQueryStringParameter_stringParameter(parameter.getKey(), parameter.getValue());
		}
		else
		{
			queryString = getQueryStringParameter_genericParameter(parameter.getKey(), parameter.getValue());
		}
		
		if(queryString == null)
			return "";
		
		
		if(this.firstParameter == true)
		{
			queryLink = " where ";
			this.firstParameter = false;
		}
		else
			queryLink = " and ";
		
		
		System.out.println("yolo: " + queryLink + queryString);
		
		return queryLink + queryString;
	}
	
	private String getQueryStringParameter_genericParameter(String label, Object value) {
		if(value == null)
			return null;
		
		return "o." + label + " = :" + label;
	}

	private String getQueryStringParameter_stringParameter(String label, Object value) {
		if(value == null)
			return null;
		
		return "o." + label + " like concat( '%' , concat(:" + label + ", '%'))";
	}
	
	private String getQueryStringParameter_collectionParameter(String label, Collection collection) {
		if(collection == null  || collection.isEmpty())
			return null;
		
		return "o." + label + " in (:" + label + ")";
	}

	private String buildQueryString(String className, Map<String, Object> parameters)
	{
		String queryString;
		
		queryString = initQueryString(className);
		
		for(Entry<String, Object> e : parameters.entrySet())
		{
			queryString = queryString.concat(getQueryStringParameter(e));
		}
		
		return queryString;
	}

	private void setCollectionParameter(Query query, String label,
			Collection collection) {
		
		if(collection == null || collection.isEmpty())
			return;
		
		query.setParameterList(label,  collection);
	}

	private void setGenericParameter(Query query, String label, Object value) {
		if(value == null )
			return;
		
		query.setParameter(label,  value);
	}

	private void setEntityParameter(Query query, String label, Object value) {
		if(value == null )
			return;

		query.setEntity(label,  value);
	}
	
	private void buildQueryParameters(Query query, Map<String, Object> parameters)
	{
		for(Entry<String, Object> e : parameters.entrySet())
		{
			if(e.getValue() instanceof Collection)
			{
				setCollectionParameter(query, e.getKey(), (Collection)e.getValue());
			}
			else
			if(e.getValue() instanceof Number
					|| e.getValue() instanceof Boolean
					|| e.getValue() instanceof String)
			{
				setGenericParameter(query, e.getKey(), e.getValue());
			}
			else
			{
				setEntityParameter(query, e.getKey(), e.getValue());
			}
		}
		
	}

	
	public Query build(Session session, String classType, Map<String,Object> parameters)
	{
		String queryString = this.buildQueryString(classType, parameters);
		
		System.out.println(queryString);
		Query query = session.createQuery(queryString);
		
		this.buildQueryParameters(query, parameters);
		
		return query;
	}
}
